%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: 
%% Progress to usefulness: 
%%
%% Implementation of a single Chord node. 
%% The Chord node ONLY takes care of the lookup function
%% (mapping keys to nodes)
%% and the synchronization of Chord state (finger tables etc).
%%
%% Persistent Chord server process. Hold state, 
%% takes care of some types of queries, and
%% spawns workers to delegate some other types of queries to.
%%
%%%%%%%%%%%%%%%%%%%%%%%

-module(chord).
-behaviour(gen_server).
-include("db.hrl").

-export([start_link/0,start_link/1]).
-export([init/1, handle_call/3,handle_cast/2,handle_info/2
        ,code_change/3,terminate/2]).

-import(chord_lib, [dbg_str/2, dbg_format/3, dbg_header/2]).
-import(chord_lib, [dbg_msg/2, dbg_msg_loc/2]).
-import(chord_lib, [get_node/1, get_pid/1, get_position/1]).
-import(chord_lib, [get_finger/2, set_finger/3, finger_start/2, get_M/0, modspace/1]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Actions to be called from the upper layers
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

handle_call({join, N2name}, _From, State) ->
        dbg_msg("join", State),
        visual:visual_chord(State, []),
        SetupModule = State#chord.setup,
        State2 = SetupModule:join(N2name, State),
        Suc = get_finger(1, State2),
        visual:visual_chord(State2, []),
        {reply, {ok, Suc#node.node}, State2};

handle_call({start_ring}, _From, State) ->
        dbg_msg("start_ring", State),
        SetupModule = State#chord.setup,
        State2 = SetupModule:start_ring(State),
        visual:visual_chord(State2, []),
        {reply, {ok}, State2};

% Return status overview
handle_call({status}, _From, State) ->
    Fmt =
"identity node: ~p
value of M: ~p
predecessor: ~p
",
    Params = [State#chord.identity,
              get_M(),
              State#chord.predecessor],
    {reply, {Fmt, Params}, State};

% Returns the whole state
handle_call({status_full}, _From, State) ->
    Fmt =
"identity node: ~p
value of M: ~p
predecessor: ~p
finger table: ~p
",
    Params = [State#chord.identity,
              get_M(),
              State#chord.predecessor,
              chord_lib:test_ft(get_M(),State)],
    {reply, {Fmt, Params}, State};

% Returns the list of finger nodes
handle_call({status_nodes}, _From, State) ->
    Nodes = [ Node#node.node || Node <- State#chord.finger_table ],
    {reply, Nodes, State};

%% Call for redundancy handling, returns an empty list atm
handle_call({successors}, _From, State) ->
        {reply, [], State};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Actions to be called from other Chord nodes
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

handle_call({set_predecessor, Pred}, _From, State) ->
        dbg_msg("set_predecessor", State),
        State2 = State#chord{ predecessor = Pred },
        visual:visual_chord(State2, []),
        {reply, {ok}, State2};

%% For all other messages, spawn a worker
%% and forward the message to the worker.
handle_call(Msg, From, State) ->
    dbg_format("chord: Got message from ~p, forwarding to worker: ~p~n", [From, Msg], State),
    % Start a worker process, include state for nodelist
    {ok,Pid} = chord_worker_sup:start_worker(State),
    gen_server:cast(Pid,{call, Msg, From}),
    {noreply, State}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Asynchronous messages
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

handle_cast({update_finger_table, S, I}, State) ->
        dbg_msg("update_finger_table", State),
        State2 = chord_aggressive:update_finger_table(S, I, State),
        visual:visual_chord(State2, []),
        {noreply, State2};

handle_cast({notify, N}, State) ->
        dbg_msg("notify", State),
        State2 = chord_stabilized:notify(N, State),
        visual:visual_chord(State2, []),
        {noreply, State2};

%% For all other messages, spawn a worker
%% and forward the message to the worker.
handle_cast(Msg, State) ->
    dbg_format("chord: Got cast, forwarding to worker: ~p~n", [Msg], State),
    % Start a worker process, include state for nodelist
    {ok,Pid} = chord_worker_sup:start_worker(State),
    gen_server:cast(Pid,{cast, Msg}),
    {noreply, State}.

%%%%%%%%%%%%%%%%
%%
%%     OTP
%%
%%%%%%%%%%%%%%%%

init(_Params) ->
  State = chord_lib:create_state(),
  io:fwrite("Node ~p:~p has been spawned at position ~B.~n",
            [get_node(State), get_pid(State), get_position(State)]),
  {ok, State}.

start_link() ->
    Args = #chordparams{},
    io:format("Loading Chord Network Module\n"),
    gen_server:start_link({local,?NETWORK},?MODULE,Args,[]).

start_link(Args) ->
    io:format("Loading Chord Network Module\n"),
    gen_server:start_link({local,?NETWORK},?MODULE,Args,[]).

% Function called when terminated
%
terminate(_Reason,_State) ->
    io:format("Terminating Chord module~n").

handle_info(stabilize, State) ->
    dbg_msg("stabilize timer interval", State),
    State2 = chord_stabilized:stabilize(State),
    {noreply, State2};

handle_info(fix_fingers, State) ->
    dbg_msg("fix fingers timer interval", State),
    State2 = chord_stabilized:fix_fingers(State),
    {noreply, State2};

handle_info(Info, State) ->
    io:format("Received info message: ~w~n", Info),
    {noreply ,State}.

code_change(_OldVsn, _State, _Extra) ->
    undefined.

